
<html><head>
<title>flibs/funit - flibs</title>
<style type="text/css"><!--
    HTML {
	background: 	#FFFFFF;
	color: 		black;
    }
    BODY {
	background: 	#FFFFFF;
	color:	 	black;
    }
    DIV.doctools {
	margin-left:	10%;
	margin-right:	10%;
    }
    DIV.doctools H1,DIV.doctools H2 {
	margin-left:	-5%;
    }
    H1, H2, H3, H4 {
	margin-top: 	1em;
	font-family:	sans-serif;
	font-size:	large;
	color:		#005A9C;
	background: 	transparent;
	text-align:		left;
    }
    H1.title {
	text-align: center;
    }
    UL,OL {
	margin-right: 0em;
	margin-top: 3pt;
	margin-bottom: 3pt;
    }
    UL LI {
	list-style: disc;
    }
    OL LI {
	list-style: decimal;
    }
    DT {
	padding-top: 	1ex;
    }
    UL.toc,UL.toc UL, UL.toc UL UL {
	font:		normal 12pt/14pt sans-serif;
	list-style:	none;
    }
    LI.section, LI.subsection {
	list-style: 	none;
	margin-left: 	0em;
	text-indent:	0em;
	padding: 	0em;
    }
    PRE {
	display: 	block;
	font-family:	monospace;
	white-space:	pre;
	margin:		0%;
	padding-top:	0.5ex;
	padding-bottom:	0.5ex;
	padding-left:	1ex;
	padding-right:	1ex;
	width:		100%;
    }
    PRE.example {
	color: 		black;
	background: 	#f5dcb3;
	border:		1px solid black;
    }
    UL.requirements LI, UL.syntax LI {
	list-style: 	none;
	margin-left: 	0em;
	text-indent:	0em;
	padding:	0em;
    }
    DIV.synopsis {
	color: 		black;
	background: 	#80ffff;
	border:		1px solid black;
	font-family:	serif;
	margin-top: 	1em;
	margin-bottom: 	1em;
    }
    UL.syntax {
	margin-top: 	1em;
	border-top:	1px solid black;
    }
    UL.requirements {
	margin-bottom: 	1em;
	border-bottom:	1px solid black;
    }
--></style>
</head>
<! -- Generated from file 'funit/funit.man' by tcllib/doctools with format 'html'
   -->
<! -- Copyright &copy; 2006 Arjen Markus &lt;arjenmarkus@sourceforge.net&gt;
   -->
<! -- CVS: $Id: funit.html,v 1.2 2013/05/13 08:03:15 knystrom Exp $ flibs/funit.n
   -->
<body><div class="doctools">
<h1 class="title">flibs/funit(n) 1.1  &quot;flibs&quot;</h1>
<div id="name" class="section"><h2><a name="name">Name</a></h2>
<p>flibs/funit - Unit testing</p>
</div>
<div id="toc" class="section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="toc">
<li class="section"><a href="#toc">Table Of Contents</a></li>
<li class="section"><a href="#synopsis">Synopsis</a></li>
<li class="section"><a href="#section1">Description</a></li>
<li class="section"><a href="#section2">ROUTINES</a></li>
<li class="section"><a href="#section3">TODO</a></li>
<li class="section"><a href="#copyright">Copyright</a></li>
</ul>
</div>
<div id="synopsis" class="section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="synopsis">
<ul class="syntax">
<li><a href="#1">runtests.bat</a></li>
<li><a href="#2">runtests.sh</a></li>
<li><a href="#3">runtests.tcl</a></li>
<li><a href="#4"><b class="cmd">call runtests( testproc )</b></a></li>
<li><a href="#5"><b class="cmd">call test( proc, text )</b></a></li>
<li><a href="#6"><b class="cmd">call assert_true( cond, text )</b></a></li>
<li><a href="#7"><b class="cmd">exists = funit_file_exists( filename )</b></a></li>
<li><a href="#8"><b class="cmd">call funit_get_lun( lun )</b></a></li>
<li><a href="#9"><b class="cmd">call funit_remove_file( filename )</b></a></li>
<li><a href="#10"><b class="cmd">call funit_make_empty_file( filename )</b></a></li>
</ul>
</div>
</div>
<div id="section1" class="section"><h2><a name="section1">Description</a></h2>
<p><em>JUnit</em> is a well-known facility for defining and running unit
tests in Java programs. The <em>funit</em> framework was inspired by
that facility. It is not as good-looking as JUnit, by no means:</p>
<ul class="itemized">
<li><p>It has no graphical user-interface</p></li>
<li><p>As Fortran does not allow introspection, the test routines can not
be detected automatically, instead as a programmer you need to set up a
high-level routine yourself that collects all the unit tests.</p></li>
<li><p>A runtime error, like division by zero, may lead to a termination of
the program. There is no (portable) way to catch these. Instead, the
framework relies on a batch file or shell script to repeatedly start the
program until all tests are run.</p></li>
</ul>
<p>Despite these limitations, <em>funit</em> can be a great help:</p>
<ul class="itemized">
<li><p>The code to test the various components (subroutines, functions, tasks
consisting of several program units) can be combined with the program
itself, without interfering with the ordinary code.</p>
<p>This is achieved by defining a single routine (test_all, say) that runs
all the unit tests and that is called via the provided routine
<em>runtests</em>:</p>
<pre class="example">
program myprog
    ...
!
! The routine runtests will check if unit tests are requested
! If not, it will return immediately. This way we make sure
! the unit tests remain part of the program.
!
! The routine test_all runs all unit tests
! (see the dataproc_testing module)
!
    call runtests( test_all )
!
! Ordinary processing
!
    ...
end program
</pre>
<p>The routine runtests checks if there is a file &quot;funit.run&quot;. If there is
such a file, it will run the given subroutine. Otherwise it will return
and the rest of the program is executed.</p></li>
<li><p>Because the test code is incorporated in the program itself, it is less
likely that they evolve independently: changes in the argument lists of
the subroutines and functions may lead to compile errors in the test
code.</p></li>
<li><p>There is no need to set up a whole new program for testing portions of
the program.</p></li>
</ul>
<p>The source file &quot;test_funit.f90&quot; illustrates how to use the funit
framework:</p>
<ul class="itemized">
<li><p>The main program calls the routine &quot;runtests&quot; and passes it the argument
&quot;test_all&quot;, a routine defined in a module called &quot;dataproc_testing&quot;.</p></li>
<li><p>The routine &quot;test_all&quot; consists of nothing but calls to the generic
routine &quot;test&quot;:</p>
<pre class="example">
subroutine test_all
    call test( test_no_file, &quot;Read non-existent file&quot; )
    call test( test_empty_file, &quot;Read an empty file&quot; )
    call test( test_invalid_file, &quot;Read an invalid file&quot; )
    call test( test_ordinary_file, &quot;Read an ordinary file&quot; )
end subroutine test_all
</pre>
</li>
<li><p>The module includes a source file &quot;funit_test.f90&quot; which defines the
generic subroutine &quot;test&quot;, thereby creating a copy <em>local</em> to
the module. It should also define two auxiliary routines,
<em>prolog</em> and <em>epilog</em> that can be used for code that is
common to all unit tests.</p></li>
<li><p>The generic routine &quot;test&quot; checks whether a particular unit
test needs to be run (via the test number) and then runs the subroutine
that was passed as one of its arguments. One such routine looks like
this:</p>
<pre class="example">
subroutine test_no_file
    integer :: nodata
    real    :: vmean, vmin, vmax
    call funit_remove_file( 'no_such_file' )
    call write_name( 'no_such_file' )
    call open_files
    call process_data( nodata, vmean, vmax, vmin )
    call assert_true( nodata == 0, &quot;No data read&quot; )
end subroutine test_no_file
</pre>
<p>The assertion is used to check that the result is as expected.</p></li>
<li><p>The program contains some deliberate errors and the resulting
log file looks like this&quot;:</p>
<pre class="example">
Test: Read non-existent file
Test: Read an empty file
Test: Read an invalid file
forrtl: severe (59): list-directed I/O syntax error, unit 11, file c:\arjen\flibs\tests\funit\invalid_file
Image              PC        Routine            Line        Source
test_funit.exe     004151B9  Unknown               Unknown  Unknown
test_funit.exe     00415017  Unknown               Unknown  Unknown
test_funit.exe     004141F4  Unknown               Unknown  Unknown
test_funit.exe     00414629  Unknown               Unknown  Unknown
test_funit.exe     00409C05  Unknown               Unknown  Unknown
test_funit.exe     004095FB  Unknown               Unknown  Unknown
test_funit.exe     0040144B  Unknown               Unknown  Unknown
test_funit.exe     00401FE9  Unknown               Unknown  Unknown
test_funit.exe     00401A2C  Unknown               Unknown  Unknown
test_funit.exe     00401BB3  Unknown               Unknown  Unknown
test_funit.exe     0040294A  Unknown               Unknown  Unknown
test_funit.exe     0040232E  Unknown               Unknown  Unknown
test_funit.exe     0044A1E9  Unknown               Unknown  Unknown
test_funit.exe     00433519  Unknown               Unknown  Unknown
kernel32.dll       7C816D4F  Unknown               Unknown  Unknown
Incrementally linked image--PC correlation disabled.
Test: Read an ordinary file
Number of failed assertions:                    0
Number of runs needed to complete the tests:    3
</pre>
</li>
</ul>
<p>The program is run via one of the following files:</p>
<dl class="definitions">
<dt><a name="1">runtests.bat</a></dt>
<dd><p>A batch file for use under MS Windows</p></dd>
<dt><a name="2">runtests.sh</a></dt>
<dd><p>A Bourne shell script for use under UNIX/Linux or similar systems, like
Cygwin or Mingw.</p></dd>
<dt><a name="3">runtests.tcl</a></dt>
<dd><p>A Tcl program that presents a simple graphical user-interface</p></dd>
</dl>
</div>
<div id="section2" class="section"><h2><a name="section2">ROUTINES</a></h2>
<p>The module funit contains the following subroutines and functions:</p>
<dl class="definitions">
<dt><a name="4"><b class="cmd">call runtests( testproc )</b></a></dt>
<dd><p>Routine to start the unit tests. It checks if the file &quot;funit.run&quot;
exists. If so, it will call the subroutine <em>testproc</em> that was
passed. Otherwise it will simply return, so that the ordinary program
execution may continue.</p>
<p>If the subroutine testproc returns, the program stops.</p>
<dl class="arguments">
<dt>subroutine <i class="arg">testproc</i></dt>
<dd><p>Subroutine that calls the individual test routines. It takes no
arguments. It wil generally exist of a series of calls to the
routine <em>test</em> - see below.</p></dd>
</dl></dd>
<dt><a name="5"><b class="cmd">call test( proc, text )</b></a></dt>
<dd><p>Routine to run the individual unit test routine (emph proc). It decides
if the test has not run yet and if so, the test routine is called.
Otherwise it is skipped.</p>
<p><em>test</em> takes care of all administrative details.</p>
<p>Note: to make it possible to use <em>private</em> unit test routines,
the source code of this subroutine is kept in a separate file,
<em>funit_test.f90</em> that should be included in an appropriate
place in the program's sources. This way, you can make it a private
routine in each module. The only public access to the unit testing
routines is then via the subroutine <em>testproc</em> that is passed to
<em>runtests</em>.</p>
<dl class="arguments">
<dt>subroutine <i class="arg">proc</i></dt>
<dd><p>Subroutine that implements an individual unit test. It takes no
arguments. Within each such subroutine the complete unit test is run.</p></dd>
<dt>character(len=*), intent(in) <i class="arg">text</i></dt>
<dd><p>Text describing the particular unit test. It is printed in the log
file.</p></dd>
</dl></dd>
<dt><a name="6"><b class="cmd">call assert_true( cond, text )</b></a></dt>
<dd><p>Routine to check that a condition is true. If not, a message is printed
in the log file and the number of failures is increased.</p>
<dl class="arguments">
<dt>logical <i class="arg">cond</i></dt>
<dd><p>The condition to be checked</p></dd>
<dt>character(len=*), intent(in) <i class="arg">text</i></dt>
<dd><p>Text describing the condition</p></dd>
</dl></dd>
<dt><a name="7"><b class="cmd">exists = funit_file_exists( filename )</b></a></dt>
<dd><p>Logical function to check that a particular file exists</p>
<dl class="arguments">
<dt>character(len=*), intent(in) <i class="arg">filename</i></dt>
<dd><p>Name of the file to be checked</p></dd>
</dl></dd>
<dt><a name="8"><b class="cmd">call funit_get_lun( lun )</b></a></dt>
<dd><p>Subroutine to get a free LU-number</p>
<dl class="arguments">
<dt>integer, intent(out) <i class="arg">lun</i></dt>
<dd><p>Next free LU-number</p></dd>
</dl></dd>
<dt><a name="9"><b class="cmd">call funit_remove_file( filename )</b></a></dt>
<dd><p>Subroutine to remove (delete) a file</p>
<dl class="arguments">
<dt>character(len=*), intent(in) <i class="arg">filename</i></dt>
<dd><p>Name of the file to be removed</p></dd>
</dl></dd>
<dt><a name="10"><b class="cmd">call funit_make_empty_file( filename )</b></a></dt>
<dd><p>Subroutine to make a new, empty file</p>
<dl class="arguments">
<dt>character(len=*), intent(in) <i class="arg">filename</i></dt>
<dd><p>Name of the file to be created</p></dd>
</dl></dd>
</dl>
</div>
<div id="section3" class="section"><h2><a name="section3">TODO</a></h2>
<p>The following things are still left to do:</p>
<ul class="itemized">
<li><p>Proper inclusion of the routine <em>prolog</em> and <em>epilog</em></p></li>
<li><p>Extension of the set of assertion routines</p></li>
</ul>
</div>
<div id="copyright" class="section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2006 Arjen Markus &lt;arjenmarkus@sourceforge.net&gt;</p>
</div>
</div></body></html>